﻿using System;
using System.Collections.Concurrent;
using RabbitMQ.Client;
namespace Athena.RabbitMQ.Implementations
{
    using Resources;
    public class RabbitMQConnection : IMQConnection, IDisposable
    {
        private ConcurrentDictionary<string, Tuple<IConnection, IModel>> _connectionCacheDictionary;
        private bool _isDisposable;

        public RabbitMQConnection()
        {
            _isDisposable = false;
            _connectionCacheDictionary = new ConcurrentDictionary<string, Tuple<IConnection, IModel>>();
        }


        private string BuildRabbitMQConfigureString(IRabbitMQConfigure rabbitMQConfigure)
        {
            return string.Format(RabbitMQResource.HostFormatter,
                rabbitMQConfigure.UserName,
                rabbitMQConfigure.Password,
                rabbitMQConfigure.HostName,
                RabbitMQResource.DefaultPort,
                rabbitMQConfigure.VirtualHost
            );
        }

        public IConnection CreateConnection(IRabbitMQConfigure rabbitMQConfigure)
        {
            return CreateRabbitMQConnectionInfo(rabbitMQConfigure).Item1;
        }

        public IModel CreateModel(IRabbitMQConfigure rabbitMQConfigure) {
            return CreateRabbitMQConnectionInfo(rabbitMQConfigure).Item2;
        }

        public IConnection CreateConnection(string uri)
        {
            return CreateRabbitMQConnectionInfo(uri).Item1;
        }

        public IModel CreateModel(string uri)
        {
            return CreateRabbitMQConnectionInfo(uri).Item2;
        }

        /// <summary>
        /// 创建Connection
        /// </summary>
        /// <param name="rabbitMQConfigure"></param>
        /// <returns></returns>
        private Tuple<IConnection, IModel> CreateRabbitMQConnectionInfo(IRabbitMQConfigure rabbitMQConfigure)
        {
            var rabbitMQConfigureString = BuildRabbitMQConfigureString(rabbitMQConfigure);
            if (_connectionCacheDictionary.ContainsKey(rabbitMQConfigureString))
            {
                return _connectionCacheDictionary[rabbitMQConfigureString];
            }
            var connectionFactory = new ConnectionFactory
            {
                UserName = rabbitMQConfigure.UserName,
                Password = rabbitMQConfigure.Password,
                VirtualHost = rabbitMQConfigure.VirtualHost,
                HostName = rabbitMQConfigure.HostName,

            };
            var connection = connectionFactory.CreateConnection();
            var model = connection.CreateModel();
            _connectionCacheDictionary.TryAdd(rabbitMQConfigureString, new Tuple<IConnection, IModel>(connection, model));
            return _connectionCacheDictionary[rabbitMQConfigureString];
        }

        /// <summary>
        /// 创建Connection
        /// </summary>
        /// <param name="uri">amqp://user:pass@hostName:port/vhost</param>
        /// <returns></returns>
        public Tuple<IConnection, IModel> CreateRabbitMQConnectionInfo(string uri)
        {
            if (_connectionCacheDictionary.ContainsKey(uri))
            {
                return _connectionCacheDictionary[uri];
            }

            var connectionFactory = new ConnectionFactory
            {
                Uri = new Uri(uri)
            };
            var connection = connectionFactory.CreateConnection();
            var model = connection.CreateModel();
            _connectionCacheDictionary.TryAdd(uri, new Tuple<IConnection, IModel>(connection, model));
            return _connectionCacheDictionary[uri];
        }



        public void Dispose()
        {
            if (!_isDisposable)
            {
                foreach (var item in _connectionCacheDictionary)
                {
                    item.Value.Item2.Close();
                    item.Value.Item1.Close();
                }
            }
        }
    }
}
